這篇記錄我在Udemy的JS課程上課筆記 (不斷更新)
call by value & call by reference
在js中,任何基本型別的變數皆為call by value,而object或是函式的參數則是call by reference
call by value: 當一個變數使用 = 指向另一個變數時,二者在記憶體存放的位址是分開的,也就是說變數b改變了並不會影響變數a
1 2 3 4 5 6 7 8 9
| const a = 3; let b = a;
console.log(a); console.log(b);
b = 4; console.log(a); console.log(b);
|
call by reference: 二個物件皆放在同一個記憶體位址,當一個物件改變也會影響到另一個物件
1 2 3 4 5 6 7 8 9
| const a = { greeting: 'Hi' }; const b = a;
console.log(a); console.log(b);
b.greeting = 'Hello'; console.log(a); console.log(b);
|
有了這個觀念之後,之後操作物件或傳參數至function時就要注意會不會動到原來的值。
object, function and this
javascript的this常讓人感到困惑,先看個例子
1 2 3 4 5
| function a() { console.log(this); }
a();
|
當呼叫a時會印出window object
1 2 3 4 5 6 7 8
| const b = { name: 'Object', log: function() { console.log(this); } }
b.log();
|
上面這個例子,this印出來會是b object的內容
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const b = { name: 'Object', log: function() { console.log(this); const setName = newName => { this.name = newName; } setName('Updated object'); console.log(this); } }
b.log();
|
這次加入setName函式至log method中,並且該函式會改變this.name,此時結果會如何呢?
1 2
| Object { name: 'Object', log: function } Object { name: 'Object', log: function }
|
setName並沒有改變b object,而是改到window object
這也是js原始設計的小缺點,如果我們要讓setName改變b object,則需要加個變數:
1 2 3 4 5 6 7 8 9 10 11 12 13
| const b = { name: 'Object', log: function() { const self = this; console.log(self); const setName = newName => { self.name = newName; } setName('Updated object'); console.log(self); } }
|
透過self指向b的記憶體位址,在setName函式裡即可正確的更動name。
call(), apply() and bind()
11/24更新
在Javascript裡Function是一種特殊的object,它有可執行的程式碼(CODE property),NAME(可為空,即是匿名著函式)以及這裡要介紹的call, apply和bind
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const person = { firstName: 'Alex', lastName: 'Liang', getFullName: function() { return `${this.firstName} ${this.lastName}`; } }
const logName = (lang1, lang2) => { console.info(`Logged: ${this.getFullName()}`); };
const logPersonName = logName.bind(person);
logPersonName();
logName.call(person, 'en', 'cht');
logName.apply(person, ['en', 'cht']);
|
此段程式碼使用bind將logName函式和person物件結合並產生新的函式logPersonName
這也表示透過bind能改變函式內this的對象
而call不需要做出一個新的函式,直接將person傳入也能達成一樣的效果;apply和call不同之處在於傳入的參數放在array裡,其效果也是一樣。
這三個函式的應用可以參考下列程式碼
1 2 3 4 5 6 7 8
|
const person2 = { firstName: 'Ben', lastName: 'Simmons' };
person.getFullName.apply(person2);
|
透過apply,我們讓person2使用getFullName
1 2 3 4 5 6 7 8
| function multiply(a, b) { return a*b; }
const multipleByTwo = multiply.bind(this, 2);
console.info(multipleByTwo(4));
|
透過事先設定的參數,我們可以建立許多函式做組合,這也是functional programming的基礎。